package detect

import (
	"sync"

	"gitee.com/liumou_site/gns/ping"
	"gitee.com/liumou_site/gns/port"
)

// OnlineDetector 综合检测器，需通过构造函数初始化
// 用法与port模块一致

type OnlineDetector struct {
	Pinger  *ping.Ping
	Checker *port.PortChecker
	Port    int
	Ips     []string
}

// NewOnlineDetector 构造函数
func NewOnlineDetector(ips []string, port int, pinger *ping.Ping, checker *port.PortChecker) *OnlineDetector {
	return &OnlineDetector{
		Pinger:  pinger,
		Checker: checker,
		Port:    port,
		Ips:     ips,
	}
}

// Detect 综合检测方法，返回 []*OnlineDetectResult
func (od *OnlineDetector) Detect() []*OnlineDetectResult {
	var results []*OnlineDetectResult
	if len(od.Ips) == 0 {
		return results
	}
	var wg sync.WaitGroup
	var mu sync.Mutex
	for _, ip := range od.Ips {
		wg.Add(1)
		go func(ip string) {
			defer wg.Done()
			var pingOnline, portOpen, dnsOnline bool
			var pingErr, portErr string
			var innerWg sync.WaitGroup
			innerWg.Add(3)
			go func() {
				defer innerWg.Done()
				err, loss := od.Pinger.Cmd(ip, 1)
				pingOnline = (err == nil && loss < 100)
				if err != nil {
					pingErr = err.Error()
				}
			}()
			go func() {
				defer innerWg.Done()
				res := od.Checker.CheckTCP(ip, od.Port)
				portOpen = res.Success > 0
				if res.Failed > 0 && res.Success == 0 {
					portErr = "all attempts failed"
				}
			}()
			go func() {
				defer innerWg.Done()
				res := od.Checker.CheckUDP(ip, 53)
				dnsOnline = res.Success > 0
			}()
			innerWg.Wait()
			res := &OnlineDetectResult{
				IP:         ip,
				PingOnline: pingOnline,
				PingErr:    pingErr,
				Port:       od.Port,
				PortOpen:   portOpen,
				PortErr:    portErr,
				Online:     pingOnline || portOpen || dnsOnline,
			}
			mu.Lock()
			results = append(results, res)
			mu.Unlock()
		}(ip)
	}
	wg.Wait()
	return results
}
